﻿Public Class characterData
#Region "Constants"
    'We will use these string arrays to get the integer value for the corresponding item in the corresponding enumerations
    Private Shared Sexs As String() = New String() {"male", "female"}
    Private Shared Vocations As String() = New String() {"None", "Paladin", "Royal Paladin", "Druid", "Elder Druid", "Knight", "Elite Knight", "Sorcerer", "Master Sorcerer"}
    Private Shared Months As String() = New String() {"BlankCauseDatesAre1IndexedNot0", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}
#End Region

#Region "Enums"
    Public Enum CharacterSex As Integer
        Male = 0
        Female = 1
    End Enum
    Public Enum CharacterProfession As Integer
        None = 0
        Paladin = 1
        RoyalPaladin = 2
        Druid = 3
        ElderDruid = 4
        Knight = 5
        EliteKnight = 6
        Sorcerer = 7
        MasterSorcerer = 8
    End Enum
    Public Enum CharacterDeath As Integer
        PVM = 0
        PVP = 1
    End Enum
#End Region

#Region "Structures"
    Public Structure characterSexData
        Public sexType As CharacterSex
        Public sexName As String
    End Structure

    Public Structure characterProfessionData
        Public vocationType As CharacterProfession
        Public vocationName As String
        Public isPromoted As Boolean
    End Structure

    Public Structure characterGuildData
        Public hasGuild As Boolean
        Public name As String
        Public rank As String
    End Structure

    Public Structure characterDeathData
        Public deathType As CharacterDeath
        Public level As Integer
        Public [date] As System.DateTime
        Public killers As String()
        Public assisters As String()
    End Structure
#End Region

#Region "Private Variables"
    Private _name As String
    Private _sex As characterSexData
    Private _profession As characterProfessionData
    Private _level As Integer
    Private _world As String
    Private _residence As String
    Private _guild As characterGuildData
    Private _deaths As characterDeathData()
#End Region

#Region "Properties"
    Public ReadOnly Property Name() As String
        Get
            Return _name
        End Get
    End Property
    Public ReadOnly Property Sex() As characterSexData
        Get
            Return _sex
        End Get
    End Property
    Public ReadOnly Property Profession() As characterProfessionData
        Get
            Return _profession
        End Get
    End Property
    Public ReadOnly Property Level() As Integer
        Get
            Return _level
        End Get
    End Property
    Public ReadOnly Property World() As String
        Get
            Return _world
        End Get
    End Property
    Public ReadOnly Property Residence() As String
        Get
            Return _residence
        End Get
    End Property
    Public ReadOnly Property Guild() As characterGuildData
        Get
            Return _guild
        End Get
    End Property
    Public ReadOnly Property Deaths() As characterDeathData()
        Get
            Return _deaths
        End Get
    End Property
#End Region

#Region "Construction"
    ''' <summary>
    ''' Obtains a characters data from a given HTML webpage.
    ''' </summary>
    ''' <param name="HTMLData">HTML data from the characters webpage.</param>
    ''' <returns>A characterData object representing the character.</returns>
    ''' <remarks></remarks>
    Public Shared Function ParseFromWebsiteData(ByVal HTMLData As String) As characterData
        Dim [return] As New characterData

        [return]._name = pageStreamer.HTMLSafeMatch(HTMLData, "Name:</td><td>([^<]*)<")

        [return]._sex = ParseSexFromWebsite(HTMLData)

        [return]._profession = ParseProfessionFromWebsite(HTMLData)

        [return]._level = Integer.Parse(pageStreamer.HTMLSafeMatch(HTMLData, "Level:</td><td>([^<]*)</td>"))
        [return]._world = pageStreamer.HTMLSafeMatch(HTMLData, "World:</td><td>([^<]*)<\/td>")
        [return]._residence = pageStreamer.HTMLSafeMatch(HTMLData, "Residence:</td><td>([^<]*)</td>")

        [return]._guild = ParseGuildFromWebsite(HTMLData)

        [return]._deaths = ParseDeathsFromWebsiteData(HTMLData)
        Return [return]
    End Function

    ''' <summary>
    ''' An internal helper which helps ParseFromWebsiteData() parse the sex.
    ''' </summary>
    ''' <param name="HTMLData">The HTML data of the characters webpage.</param>
    ''' <returns>A characterSexData object representing the characters sex.</returns>
    ''' <remarks></remarks>
    Private Shared Function ParseSexFromWebsite(ByVal HTMLData As String) As characterSexData
        Dim [return] As New characterSexData
        [return].sexName = pageStreamer.HTMLSafeMatch(HTMLData, "Sex:</td><td>([^<]*)</td>")
        [return].sexType = Array.IndexOf(Sexs, [return].sexName)
        Return [return]
    End Function

    ''' <summary>
    ''' An internal helper which helps ParseFromWebsiteData() parse the players vocation.
    ''' </summary>
    ''' <param name="HTMLData">The HTML data of the characters webpage.</param>
    ''' <returns>A characterProfessionData object representing the characters profession.</returns>
    ''' <remarks></remarks>
    Private Shared Function ParseProfessionFromWebsite(ByVal HTMLData As String) As characterProfessionData
        Dim [return] As New characterProfessionData
        [return].vocationName = pageStreamer.HTMLSafeMatch(HTMLData, "Profession:</td><td>([^<]*)</td>")
        [return].vocationType = Array.IndexOf(Vocations, [return].vocationName)
        If ([return].vocationType > 0) Then
            [return].isPromoted = ([return].vocationType Mod 2 = 0)
        End If

        Return [return]
    End Function

    ''' <summary>
    ''' An internal helper which helps ParseFromWebsiteData() parse the guild information.
    ''' </summary>
    ''' <param name="HTMLData">The HTML data of the characters webpage.</param>
    ''' <returns>A characterGuildData object representing the characters guild status.</returns>
    ''' <remarks></remarks>
    Private Shared Function ParseGuildFromWebsite(ByVal HTMLData As String) As characterGuildData
        Dim [return] As New characterGuildData
        Dim GuildSubString As String = pageStreamer.HTMLSafeMatch(HTMLData, "Membership:</td><td>(.*?)</td>")
        [return].hasGuild = (GuildSubString <> "")
        If ([return].hasGuild) Then
            [return].rank = pageStreamer.HTMLSafeMatch(GuildSubString, "(.*) of the <a href")
            [return].name = pageStreamer.HTMLSafeMatch(GuildSubString, ">([^<]*)</a>")
        End If
        Return [return]
    End Function

    ''' <summary>
    ''' An internal helper which helps ParseFromWebsiteData() parse the deathlist. Also the messiest coded function in this program.
    ''' </summary>
    ''' <param name="HTMLData">The HTML data of the characters webpage.</param>
    ''' <returns>A characterDeathData array representing the deathlist.</returns>
    ''' <remarks></remarks>
    Private Shared Function ParseDeathsFromWebsiteData(ByVal HTMLData As String) As characterDeathData()
        Dim [return] As New List(Of characterDeathData)

        Dim DeathSubString As String = pageStreamer.HTMLSafeMatch(HTMLData, "Deaths</b></td></tr>(.*?)</table>")
        Dim Deaths As String() = pageStreamer.HTMLSafeMatches(DeathSubString, "<td width=""25%"" valign=""top"" >(.*?)\.</td>")

        For Each fullDeath As String In Deaths
            Dim currentDeath As New characterDeathData

            fullDeath = fullDeath.Replace("<td>", "").Replace("</td>", "")

            Dim DateSubString As String = fullDeath.Substring(0, 26)
            Dim Death As String = fullDeath.Remove(0, 26)

            currentDeath.date = ParseDeathDateFromWebsiteData(DateSubString)

            If (Death.StartsWith("Died")) Then
                currentDeath.deathType = CharacterDeath.PVM
            Else
                currentDeath.deathType = CharacterDeath.PVP
            End If

            currentDeath.level = Integer.Parse(pageStreamer.HTMLSafeMatch(Death, "Level (\d*)"))

            'Finally, we separate the assists from kills and then add them to the respective lists
            If (currentDeath.deathType = CharacterDeath.PVM) Then
                currentDeath.killers = Death.Split(",")
            Else
                Dim killersSubString As String = Death
                Dim assistsSubString As String = pageStreamer.HTMLSafeMatch(Death, "Assisted by(.*)")

                If (assistsSubString <> String.Empty) Then
                    killersSubString = Death.Replace(assistsSubString, "")
                    currentDeath.assisters = pageStreamer.HTMLSafeMatches(assistsSubString, "<a href=[^>]*>([^<]*)</a>")
                End If
                currentDeath.killers = pageStreamer.HTMLSafeMatches(killersSubString, "<a href=[^>]*>([^<]*)</a>")
            End If

            [return].Add(currentDeath)
        Next

        Return [return].ToArray
    End Function
    ''' <summary>
    ''' An internal helper which helps ParseDeathsFromWebsiteData() parse the date.
    ''' </summary>
    ''' <param name="DateSubString">The DateSubString from the death.</param>
    ''' <returns>A System.DateTime object representing the date.</returns>
    ''' <remarks></remarks>
    Private Shared Function ParseDeathDateFromWebsiteData(ByVal DateSubString As String) As DateTime
        Dim DaySubString As String = DateSubString.Split(",")(0)
        Dim TimeSubString As String = pageStreamer.HTMLSafeMatch(DateSubString, ".*, (.*) CEST")

        Dim DaySplit As String() = DaySubString.Split(" ")
        Dim Month As Integer = Array.IndexOf(Months, DaySplit(0))
        Dim Day As Integer = Integer.Parse(DaySplit(1))
        Dim Year As Integer = Integer.Parse(DaySplit(2))

        Dim TimeSplit As String() = TimeSubString.Split(":")
        Dim Hour As Integer = Integer.Parse(TimeSplit(0))
        Dim Minute As Integer = Integer.Parse(TimeSplit(1))
        Dim Second As Integer = Integer.Parse(TimeSplit(2))

        Return New DateTime(Year, Month, Day, Hour, Minute, Second)
    End Function
#End Region
End Class
